use crate::{
    CodeMetrics, TrendReport, QualityIssue, MetricsSummary,
    DateTime, Utc, Serialize, Deserialize,
};
use std::collections::HashMap;
use std::fmt;

/// Comprehensive analytics report
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnalyticsReport {
    /// Report metadata
    pub metadata: ReportMetadata,
    /// Executive summary
    pub executive_summary: ExecutiveSummary,
    /// Detailed metrics
    pub metrics: CodeMetrics,
    /// Quality issues found
    pub quality_issues: Vec<QualityIssue>,
    /// Trend analysis
    pub trend_analysis: Option<TrendReport>,
    /// Recommendations
    pub recommendations: Vec<Recommendation>,
    /// Detailed sections
    pub sections: Vec<ReportSection>,
}

/// Report metadata
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReportMetadata {
    /// Report title
    pub title: String,
    /// Generation timestamp
    pub generated_at: DateTime<Utc>,
    /// Report version
    pub version: String,
    /// Analysis scope
    pub scope: AnalysisScope,
    /// Configuration used
    pub configuration: ReportConfiguration,
}

/// Analysis scope
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnalysisScope {
    /// Project name
    pub project_name: String,
    /// Files analyzed
    pub files_analyzed: usize,
    /// Total lines of code
    pub total_lines: usize,
    /// Languages included
    pub languages: Vec<String>,
    /// Time period (for trend analysis)
    pub time_period: Option<String>,
}

/// Report configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReportConfiguration {
    /// Metrics enabled
    pub metrics_enabled: Vec<String>,
    /// Quality checks enabled
    pub quality_checks_enabled: Vec<String>,
    /// Trend analysis enabled
    pub trend_analysis_enabled: bool,
    /// Report format
    pub format: ReportFormat,
}

/// Report format options
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ReportFormat {
    Json,
    Html,
    Markdown,
    Pdf,
    Csv,
}

/// Executive summary
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExecutiveSummary {
    /// Overall quality score (0-100)
    pub overall_score: f64,
    /// Quality grade
    pub quality_grade: QualityGrade,
    /// Key findings
    pub key_findings: Vec<String>,
    /// Critical issues count
    pub critical_issues: usize,
    /// Major issues count
    pub major_issues: usize,
    /// Trend summary
    pub trend_summary: Option<String>,
    /// Top recommendations
    pub top_recommendations: Vec<String>,
}

/// Quality grade
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum QualityGrade {
    A, // 90-100
    B, // 80-89
    C, // 70-79
    D, // 60-69
    F, // < 60
}

/// Recommendation
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Recommendation {
    /// Recommendation ID
    pub id: String,
    /// Title
    pub title: String,
    /// Description
    pub description: String,
    /// Priority
    pub priority: RecommendationPriority,
    /// Category
    pub category: RecommendationCategory,
    /// Effort estimate
    pub effort: EffortEstimate,
    /// Expected impact
    pub impact: ImpactLevel,
    /// Implementation steps
    pub implementation_steps: Vec<String>,
    /// Related metrics
    pub related_metrics: Vec<String>,
}

/// Recommendation priority
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub enum RecommendationPriority {
    Low,
    Medium,
    High,
    Critical,
}

/// Recommendation category
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RecommendationCategory {
    CodeQuality,
    Performance,
    Security,
    Maintainability,
    Testing,
    Documentation,
    Architecture,
}

/// Effort estimate
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EffortEstimate {
    Minimal,  // < 1 hour
    Low,      // 1-8 hours
    Medium,   // 1-3 days
    High,     // 1-2 weeks
    VeryHigh, // > 2 weeks
}

/// Impact level
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ImpactLevel {
    Low,
    Medium,
    High,
    VeryHigh,
}

/// Report section
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReportSection {
    /// Section title
    pub title: String,
    /// Section content
    pub content: SectionContent,
    /// Subsections
    pub subsections: Vec<ReportSection>,
}

/// Section content types
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SectionContent {
    Text(String),
    Metrics(MetricsSummary),
    Chart(ChartData),
    Table(TableData),
    IssueList(Vec<QualityIssue>),
    RecommendationList(Vec<Recommendation>),
}

/// Chart data for visualizations
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChartData {
    /// Chart type
    pub chart_type: ChartType,
    /// Chart title
    pub title: String,
    /// X-axis label
    pub x_label: String,
    /// Y-axis label
    pub y_label: String,
    /// Data series
    pub series: Vec<DataSeries>,
}

/// Chart types
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ChartType {
    Line,
    Bar,
    Pie,
    Scatter,
    Histogram,
    Heatmap,
}

/// Data series for charts
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DataSeries {
    /// Series name
    pub name: String,
    /// Data points
    pub data: Vec<DataPoint>,
    /// Series color
    pub color: Option<String>,
}

/// Data point
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DataPoint {
    /// X value
    pub x: f64,
    /// Y value
    pub y: f64,
    /// Optional label
    pub label: Option<String>,
}

/// Table data
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TableData {
    /// Column headers
    pub headers: Vec<String>,
    /// Table rows
    pub rows: Vec<Vec<String>>,
    /// Optional row metadata
    pub row_metadata: Option<Vec<HashMap<String, String>>>,
}

/// Report generator
pub struct ReportGenerator {
    /// Report configuration
    config: ReportConfiguration,
}

impl ReportGenerator {
    /// Create a new report generator
    pub fn new(config: ReportConfiguration) -> Self {
        Self { config }
    }

    /// Generate a comprehensive analytics report
    pub async fn generate_report(
        &self,
        metrics: CodeMetrics,
        quality_issues: Vec<QualityIssue>,
        trend_report: Option<TrendReport>,
        scope: AnalysisScope,
    ) -> Result<AnalyticsReport, Box<dyn std::error::Error>> {
        let metadata = ReportMetadata {
            title: format!("Code Analytics Report - {}", scope.project_name),
            generated_at: Utc::now(),
            version: "1.0.0".to_string(),
            scope: scope.clone(),
            configuration: self.config.clone(),
        };

        let executive_summary = self.generate_executive_summary(&metrics, &quality_issues, &trend_report).await?;
        let recommendations = self.generate_recommendations(&metrics, &quality_issues, &trend_report).await?;
        let sections = self.generate_report_sections(&metrics, &quality_issues, &trend_report).await?;

        Ok(AnalyticsReport {
            metadata,
            executive_summary,
            metrics,
            quality_issues,
            trend_analysis: trend_report,
            recommendations,
            sections,
        })
    }

    /// Generate executive summary
    async fn generate_executive_summary(
        &self,
        metrics: &CodeMetrics,
        quality_issues: &[QualityIssue],
        trend_report: &Option<TrendReport>,
    ) -> Result<ExecutiveSummary, Box<dyn std::error::Error>> {
        let overall_score = metrics.calculate_quality_score();
        let quality_grade = match overall_score {
            score if score >= 90.0 => QualityGrade::A,
            score if score >= 80.0 => QualityGrade::B,
            score if score >= 70.0 => QualityGrade::C,
            score if score >= 60.0 => QualityGrade::D,
            _ => QualityGrade::F,
        };

        let critical_issues = quality_issues.iter()
            .filter(|issue| matches!(issue.severity, crate::quality::IssueSeverity::Critical))
            .count();

        let major_issues = quality_issues.iter()
            .filter(|issue| matches!(issue.severity, crate::quality::IssueSeverity::Major))
            .count();

        let key_findings = self.generate_key_findings(metrics, quality_issues).await?;
        let trend_summary = trend_report.as_ref().map(|_| "Trend analysis available".to_string());
        let top_recommendations = self.generate_top_recommendations(metrics, quality_issues).await?;

        Ok(ExecutiveSummary {
            overall_score,
            quality_grade,
            key_findings,
            critical_issues,
            major_issues,
            trend_summary,
            top_recommendations,
        })
    }

    /// Generate key findings
    async fn generate_key_findings(
        &self,
        metrics: &CodeMetrics,
        quality_issues: &[QualityIssue],
    ) -> Result<Vec<String>, Box<dyn std::error::Error>> {
        let mut findings = Vec::new();

        // Complexity findings
        if metrics.complexity.cyclomatic_complexity > 15.0 {
            findings.push(format!("High cyclomatic complexity detected: {:.1}", metrics.complexity.cyclomatic_complexity));
        }

        // Quality findings
        if metrics.quality.test_coverage < 80.0 {
            findings.push(format!("Low test coverage: {:.1}%", metrics.quality.test_coverage));
        }

        if metrics.quality.duplication_percentage > 5.0 {
            findings.push(format!("High code duplication: {:.1}%", metrics.quality.duplication_percentage));
        }

        // Issue findings
        if quality_issues.len() > 50 {
            findings.push(format!("High number of quality issues: {}", quality_issues.len()));
        }

        // Maintainability findings
        if metrics.maintainability.maintainability_index < 70.0 {
            findings.push(format!("Low maintainability index: {:.1}", metrics.maintainability.maintainability_index));
        }

        Ok(findings)
    }

    /// Generate top recommendations
    async fn generate_top_recommendations(
        &self,
        metrics: &CodeMetrics,
        quality_issues: &[QualityIssue],
    ) -> Result<Vec<String>, Box<dyn std::error::Error>> {
        let mut recommendations = Vec::new();

        if metrics.complexity.cyclomatic_complexity > 10.0 {
            recommendations.push("Reduce code complexity through refactoring".to_string());
        }

        if metrics.quality.test_coverage < 80.0 {
            recommendations.push("Increase test coverage to at least 80%".to_string());
        }

        if metrics.quality.duplication_percentage > 3.0 {
            recommendations.push("Eliminate code duplication".to_string());
        }

        if quality_issues.iter().any(|issue| matches!(issue.severity, crate::quality::IssueSeverity::Critical)) {
            recommendations.push("Address critical security and quality issues".to_string());
        }

        Ok(recommendations)
    }

    /// Generate detailed recommendations
    async fn generate_recommendations(
        &self,
        metrics: &CodeMetrics,
        quality_issues: &[QualityIssue],
        _trend_report: &Option<TrendReport>,
    ) -> Result<Vec<Recommendation>, Box<dyn std::error::Error>> {
        let mut recommendations = Vec::new();

        // Complexity recommendations
        if metrics.complexity.cyclomatic_complexity > 10.0 {
            recommendations.push(Recommendation {
                id: "COMPLEXITY_001".to_string(),
                title: "Reduce Cyclomatic Complexity".to_string(),
                description: "The codebase has high cyclomatic complexity which makes it harder to understand and maintain.".to_string(),
                priority: RecommendationPriority::High,
                category: RecommendationCategory::CodeQuality,
                effort: EffortEstimate::Medium,
                impact: ImpactLevel::High,
                implementation_steps: vec![
                    "Identify functions with complexity > 10".to_string(),
                    "Break down complex functions into smaller ones".to_string(),
                    "Use early returns to reduce nesting".to_string(),
                    "Extract complex conditions into well-named functions".to_string(),
                ],
                related_metrics: vec!["cyclomatic_complexity".to_string()],
            });
        }

        // Test coverage recommendations
        if metrics.quality.test_coverage < 80.0 {
            recommendations.push(Recommendation {
                id: "TESTING_001".to_string(),
                title: "Increase Test Coverage".to_string(),
                description: format!("Current test coverage is {:.1}%, which is below the recommended 80%.", metrics.quality.test_coverage),
                priority: RecommendationPriority::High,
                category: RecommendationCategory::Testing,
                effort: EffortEstimate::High,
                impact: ImpactLevel::High,
                implementation_steps: vec![
                    "Identify untested code paths".to_string(),
                    "Write unit tests for core functionality".to_string(),
                    "Add integration tests for critical workflows".to_string(),
                    "Set up automated test coverage reporting".to_string(),
                ],
                related_metrics: vec!["test_coverage".to_string()],
            });
        }

        // Security recommendations
        let security_issues = quality_issues.iter()
            .filter(|issue| matches!(issue.issue_type, crate::quality::QualityIssueType::Security(_)))
            .count();

        if security_issues > 0 {
            recommendations.push(Recommendation {
                id: "SECURITY_001".to_string(),
                title: "Address Security Issues".to_string(),
                description: format!("Found {} security issues that need immediate attention.", security_issues),
                priority: RecommendationPriority::Critical,
                category: RecommendationCategory::Security,
                effort: EffortEstimate::Medium,
                impact: ImpactLevel::VeryHigh,
                implementation_steps: vec![
                    "Review all security issues identified".to_string(),
                    "Prioritize critical security vulnerabilities".to_string(),
                    "Implement security fixes".to_string(),
                    "Add security testing to CI/CD pipeline".to_string(),
                ],
                related_metrics: vec!["security_issues".to_string()],
            });
        }

        Ok(recommendations)
    }

    /// Generate report sections
    async fn generate_report_sections(
        &self,
        metrics: &CodeMetrics,
        quality_issues: &[QualityIssue],
        trend_report: &Option<TrendReport>,
    ) -> Result<Vec<ReportSection>, Box<dyn std::error::Error>> {
        let mut sections = Vec::new();

        // Metrics overview section
        sections.push(ReportSection {
            title: "Metrics Overview".to_string(),
            content: SectionContent::Text(format!(
                "This section provides an overview of the key metrics for the analyzed codebase. \
                 The analysis covers {} lines of code across {} files.",
                metrics.lines_of_code.total_lines,
                metrics.lines_of_code.per_file.len()
            )),
            subsections: vec![
                ReportSection {
                    title: "Lines of Code".to_string(),
                    content: SectionContent::Text(format!(
                        "Total: {}, Code: {}, Comments: {}, Blank: {}",
                        metrics.lines_of_code.total_lines,
                        metrics.lines_of_code.code_lines,
                        metrics.lines_of_code.comment_lines,
                        metrics.lines_of_code.blank_lines
                    )),
                    subsections: vec![],
                },
                ReportSection {
                    title: "Complexity Metrics".to_string(),
                    content: SectionContent::Text(format!(
                        "Cyclomatic Complexity: {:.1}, Cognitive Complexity: {:.1}, Max Nesting Depth: {}",
                        metrics.complexity.cyclomatic_complexity,
                        metrics.complexity.cognitive_complexity,
                        metrics.complexity.max_nesting_depth
                    )),
                    subsections: vec![],
                },
            ],
        });

        // Quality issues section
        if !quality_issues.is_empty() {
            sections.push(ReportSection {
                title: "Quality Issues".to_string(),
                content: SectionContent::IssueList(quality_issues.to_vec()),
                subsections: vec![],
            });
        }

        // Trend analysis section
        if let Some(trends) = trend_report {
            sections.push(ReportSection {
                title: "Trend Analysis".to_string(),
                content: SectionContent::Text(format!(
                    "Trend analysis based on {} data points from {} to {}",
                    trends.period.data_points,
                    trends.period.start.format("%Y-%m-%d"),
                    trends.period.end.format("%Y-%m-%d")
                )),
                subsections: vec![],
            });
        }

        Ok(sections)
    }
}

impl fmt::Display for QualityGrade {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            QualityGrade::A => write!(f, "A (Excellent)"),
            QualityGrade::B => write!(f, "B (Good)"),
            QualityGrade::C => write!(f, "C (Fair)"),
            QualityGrade::D => write!(f, "D (Poor)"),
            QualityGrade::F => write!(f, "F (Failing)"),
        }
    }
}

impl Default for ReportConfiguration {
    fn default() -> Self {
        Self {
            metrics_enabled: vec![
                "lines_of_code".to_string(),
                "complexity".to_string(),
                "quality".to_string(),
                "maintainability".to_string(),
            ],
            quality_checks_enabled: vec![
                "code_smells".to_string(),
                "security".to_string(),
                "performance".to_string(),
            ],
            trend_analysis_enabled: true,
            format: ReportFormat::Json,
        }
    }
}
